home *** CD-ROM | disk | FTP | other *** search
/ NetNews Offline 2 / NetNews Offline Volume 2.iso / news / comp / lang / c++-part1 / 639 < prev    next >
Encoding:
Text File  |  1996-08-06  |  4.1 KB  |  145 lines

  1. Path: news.th-darmstadt.de!news
  2. From: Enno Sandner <enno@intellektik.informatik.th-darmstadt.de>
  3. Newsgroups: comp.lang.c++
  4. Subject: Re: Creating a pointer to a function "void (*ptrFunction)()"  inside a class
  5. Date: Fri, 05 Jan 1996 16:00:22 +0100
  6. Organization: Fachbereich Informatik, TH Darmstadt
  7. Message-ID: <30ED3D06.59E2B600@intellektik.informatik.th-darmstadt.de>
  8. References: <30ECA10F.3D99@ifu.net>
  9. NNTP-Posting-Host: kitz.intellektik.informatik.th-darmstadt.de
  10. Mime-Version: 1.0
  11. Content-Type: text/plain; charset=us-ascii
  12. Content-Transfer-Encoding: 7bit
  13. X-Mailer: Mozilla 2.0b4 (X11; I; SunOS 4.1.3 sun4m)
  14.  
  15. Jason Gresh wrote:
  16. > Hi,
  17. >         I am trying to create a base class that has a function that the
  18. > derived class needs to create.  In order to do this, I want to create a
  19. > pointer to a function in the base class that the derived class can then
  20. > define.  This is not a case where an override will work because the
  21. > number and names of the derived functions is not known.  Hopefully this
  22. > code sample will make this clearer:
  23. > class BaseClass
  24. > {
  25. >         int (*ptrFunction)();
  26. > }
  27. > class DerivedClass : BaseClass
  28. > {
  29. >         DerivedClass::DerivedClass();
  30. >         int myFunction(int, int);
  31. > }
  32. > DerivedClass::DerivedClass()
  33. > {
  34. >         ptrFunction = myFunction;
  35. > }
  36. > DerivedClass::myFunction(int, int)
  37. > {
  38. > // code ....
  39. > }
  40. > If I don't make myFunction part of the derived class (global),
  41. > everything works fine.  As soon as I include it in the class, I cannot
  42. > assign a pointer to it.  I am aware that pointers to functions inside
  43. > the class include the class name in some way ( this is not an issue for
  44. > global functions).  What is the casting (or other) mechanism to make
  45. > this work?
  46.  
  47. You should forget about casting in this situation.
  48. The problem is that you try to assign a pointer to
  49. a member-function to a pointer to an ordinary function.
  50. The types of both pointers are incompatible. 
  51. When 'myfunction' doesn't access any instance specific
  52. data (direct or by calling a function that does so),
  53. you can declare 'myfunction' as static and the problem
  54. will disappear.
  55. Otherwise it's not that easy, but a broadly accepted solution 
  56. is to encapsulate (member-) functions in so called functors.
  57. Usually one starts with a class that describes the common 
  58. interface of all functors of a cathegory. In your example it 
  59. may look like:
  60.  
  61.         class Functor {
  62.         public:
  63.           virtual ~Functor() {}
  64.           virtual int operator()() =0;
  65.         };
  66.  
  67. All subclasses and therefore all implementations of the Functor
  68. will provide a realization of 'operator ()'.
  69. There could for example a class 'CFunctor' which encapsulates 
  70. pointers to ordinary functions:
  71.  
  72.         class CFunctor : public Functor {
  73.  
  74.           typedef int (*F)();    
  75.  
  76.         public:
  77.           CFunction(F func) : func_(func) {}
  78.           int operator ()() { return (*func_)(); }
  79.                 private:
  80.                    F func_;
  81.                 };
  82.  
  83. Another subclass may form a wrapper to member-functions.
  84. (see below GenFunctor<T>). And finally there're maybe classes
  85. which does other fancy things.
  86. Now a possible client of the Functor uses the common interface
  87. to invoke the offered functionality:
  88.  
  89.         void f(Functor& f) { int i=f(); }
  90.  
  91. Because 'operator ()' is declared as virtual the correct implementation
  92. will be used. The client doesn't care how the functionality is invoked
  93. it just uses the Functor-interface. Thus there're no unnecessary
  94. dependencies between the client and service provider.
  95. The following example demonstrates how to wrap arbitary member-functions
  96. of type 'int (X::*)()' (where X is come class) using the functor-idiom.
  97.  
  98.     Enno
  99.  
  100. #include <iostream.h>
  101.  
  102. class Functor {
  103. public:
  104.   virtual ~Functor() {}
  105.   virtual int operator()() =0;
  106. };
  107.  
  108. template<class T> class GenFunctor : public Functor {
  109.  
  110.   typedef int (T::*MF)();
  111.  
  112.  public:
  113.   GenFunctor(T* const obj,MF func) : obj_(obj), func_(func) {}
  114.   int operator()() { return (obj_->*func_)(); }
  115.  
  116.  private:
  117.   T* const obj_;
  118.   MF func_;
  119. };
  120.  
  121. void f(Functor& f) { cout << f() << endl; }
  122.  
  123. struct A { int f() { return 1; } };
  124. struct B { int f() { return 2; } };
  125.  
  126. int main()
  127. {
  128.   A a;
  129.   B b;
  130.   GenFunctor<A> fa(&a,&A::f);
  131.   GenFunctor<B> fb(&b,&B::f);
  132.   f(fa);
  133.   f(fb);
  134.  
  135.   return 0;
  136. }
  137.